﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using InputParsing;

namespace DissipativeInputProcessing
{
    class Frame:IFrame
    {
        #region Private Stuff

        private static InputParser parser = InputParser.Instance;
        private Bitmap _image;
        private bool _updated = true;
        private bool _sourceDataUpdated = true;
        private float[,] _sourceData;
        private FramePalette _palette;
        private float _minSource;
        private float _maxSource;
        private void CreateImage()
        {
            if(Palette==null)
            {
                var result = parser.ParseToBitmap(SourceData);
                _image = result.Bitmap;
                Palette = new FramePalette
                              {
                                  MinColor = Color.Black,
                                  MaxColor = Color.White,
                                  MaxValue = result.MaxValue,
                                  MinValue = result.MinValue
                              };
                _sourceDataUpdated = false;
                _minSource = result.MinValue;
                _maxSource = result.MaxValue;
            }
            else
                _image = parser.ParseToBitmap(SourceData, _palette.MinColor, _palette.MaxColor, Palette.MinValue, Palette.MaxValue).Bitmap;
            _updated = false;
        }
        #endregion

        #region Constructors
        public Frame(float[,] source, string description="")
        {
            SourceData = source;
            Description = description;
        }
        public Frame(float[,] source, FramePalette palette, string description = "")
            : this(source, description)
        {
            Palette = palette;
        }

        public Frame(string description)
        {
            this.Description = description;
        }

        #endregion

        public Bitmap Image
        {
            get
            {
                if(_updated)
                {
                    CreateImage();
                }
                return _image;
            }
        }

        public string Description { get; private set; }

        public FramePalette Palette
        {
            get { return _palette; }
            set
            {
                if(_palette!=value)
                {
                    _palette = value;
                    _updated = true;
                }
            }
        }

        public bool IsUpToDate
        {
            get { return _updated; }
        }

        public float[,] SourceData { 
            get
            {
                return _sourceData;
            } 
            set 
            { _sourceData = value;
                _updated = true;
                _sourceDataUpdated = true;
            }
        }

        public void Update()
        {
            _updated = true;
        }
        public void Update(bool instantly)
        {
            if (instantly)
                CreateImage();
            else
                _updated = true;
        }
        public override string ToString()
        {
            return Description;
        }

        public float MinSourceValue
        {
            get
            {
                if (_sourceDataUpdated)
                    FindMinMaxFromSource();
                return _minSource;
            }
        }

        public float MaxSourceValue
        {
            get
            {
                if (_sourceDataUpdated)
                    FindMinMaxFromSource();
                return _maxSource;
            }
        }

        private void FindMinMaxFromSource()
        {
            float min = _sourceData[0,0];
            float max = min;
            for (int i = 0; i < _sourceData.GetLength(0); i++)
            {
                for (int j = 0; j < _sourceData.GetLength(1);j++ )
                {
                    if (_sourceData[i, j] < min)
                        min = _sourceData[i, j];
                    else if (_sourceData[i, j] > max)
                        max = _sourceData[i, j];
                }
            }
            _minSource = min;
            _maxSource = max;
        }
    }
}
